Q Is there a mechanism that would allow us to access each decompressed image
prior to display during playback so that we can manipulate the image data and
then hand it back for display?
A QuickTime 1.6.1 provides a function called SetTrackGWorld
. SetTrackGWorld
lets
you force a track to draw into a particular GWorld
, which can be different from
that of the entire movie. After the track is drawn, it calls your transfer
procedure to copy the track to the actual movie GWorld
. When your transfer
procedure is set, the current GWorld
is set to the correct destination.
You could also install a transfer procedure, and set the GWorld
to nil. When
you do this, your transfer procedure is called only as a notification that the
track has drawn and that no transfer is taking place. You can also manipulate
the image inside your transfer procedure. Note that calling resource-intensive
or time-consuming routines in your transfer procedure may have an adverse
effect on playback performance.
Here's an example of a transfer procedure that keeps a counter of the number of times it has been called and displays this number in the top-left corner of the movie:
pascal OSErr myTrackTransferProc(Track t, long refCon) { TransferDataHandle myTDH = (TransferDataHandle)refCon ; GrafPtr theNewWorld ; GrafPtr movieGWorld ; PixMapHandle offPixMap ; Rect movieBox ; static long index = 1 ; CGrafPtr savedWorld ; GDHandle savedDevice ; Str255 theString ; movieGWorld = (GrafPtr)((**myTDH).movieGWorld) ; theNewWorld = (GrafPtr)((**myTDH).trackGWorld) ; movieBox = (**myTDH).movieRect ; offPixMap = GetGWorldPixMap( (GWorldPtr)theNewWorld ) ; (void) LockPixels( offPixMap ) ; GetGWorld( &savedWorld, &savedDevice ); SetGWorld( (CGrafPtr)theNewWorld, nil ) ; MoveTo ( 15, 15 ); NumToString ( index++, theString ); DrawString ( theString ); // copy the image from the offscreen port // into the movies port SetGWorld( savedWorld, savedDevice ) ; CopyBits( &theNewWorld->portBits, &movieGWorld->portBits, &theNewWorld->portRect, &movieBox, srcCopy, nil ) ; (void) UnlockPixels( offPixMap ) ; } //--------------------------------------------------------------------- // define a structure to hold all the information we need in the transfer // proc. typedef struct { GWorldPtr movieGWorld ; GWorldPtr trackGWorld ; Rect movieRect ; } TransferData, *TransferDataPtr, **TransferDataHandle ; //This has the original movie gWorld, the one we created for the track and a rect // describing the movie. You can set a movie up to use this in the following way: TransferDataHandle myTDH = (TransferDataHandle)NewHandle( sizeof( TransferData )) ; Track aTrack = GetFirstTrackOfType( aMovie, VideoMediaType ) ; short trackDepth = GetFirstVideoTrackPixelDepth( aMovie ) ; if( myTDH == nil || aTrack == nil || trackDepth < 0) return ; GetTrackDimensions( aTrack, &width, &height ) ; trackDimensions.right = Fix2Long( width ); trackDimensions.bottom = Fix2Long( height ); // create the movie gWorld theErr = NewGWorld( &theNewWorld, trackDepth, &trackDimensions, nil, theNewWorldDevice, 0L ) ; CheckError( theErr, "\pCall to NewGWorld failed" ); GetMovieGWorld( aMovie, &movieGWorld, nil ) ; (**myTDH).movieGWorld = movieGWorld ; (**myTDH).trackGWorld = theNewWorld ; GetMovieBox( aMovie, &movieBox ) ; (**myTDH).movieRect = movieBox ; SetTrackGWorld( aTrack, (CGrafPtr)theNewWorld, nil, myTrackTransferProc, (long)myTDH ) ;